// 造者模式：将一个复杂对象的构建与它的表示分离，使得同样的构建过程可以创建不同的表示。
//          建造者模式是一步一步创建一个复杂的对象，它允许用户只通过指定复杂对象的类型和内容就可以构建它们，用户不需要知道内部的具体构建细节。

#include <iostream>
#include <string>

// •Product（产品）：表示被构造的复杂对象
class Car {
public:
    void setWheel(const std::string wheel) { m_wheel = wheel; }
    const std::string& getWheel() const { return m_wheel; }
    void setEngine (const std::string engine) { m_engine = engine; }
    const std::string& getEngine () const { return m_engine; }
    void setBrake (const std::string brake) { m_brake = brake; }
    const std::string& getBrake () const { return m_brake; }
    void show() const { std::cout << m_engine << ":" << m_wheel << ":" << m_brake << std::endl; }

private:
    std::string m_wheel;
    std::string m_engine;
    std::string m_brake;
};

class Builder {
public:
    virtual ~Builder() = default;
    virtual void buildWheel() = 0;
    virtual void buildEngine () = 0;
    virtual void buildBrake () = 0;
    virtual const Car* getResult() const = 0;
};

//ConcreteBuilder（具体建造者）：实现 Builder 的接口以构造和装配该产品的各个部件，定义并明确它所创建的表示，并提供一个检索产品的接口。
class BenchiBuilder : public Builder {
public:
    BenchiBuilder() { m_car = new Car; }
    virtual void buildWheel() { m_car->setWheel("BenchiWheel"); }
    virtual void buildEngine () { m_car->setEngine("BenchiEngine"); }
    virtual void buildBrake () { m_car->setBrake("BenchiBrake"); }
    virtual const Car* getResult() const { return m_car; }

private:
    Car* m_car;
};

class BaomaBuilder : public Builder {
public:
    BaomaBuilder() { m_car = new Car; }
    virtual void buildWheel() { m_car->setWheel("BaomaWheel"); }
    virtual void buildEngine () { m_car->setEngine("BaomaEngine"); }
    virtual void buildBrake () { m_car->setBrake("BaomaBrake"); }
    virtual const Car* getResult() const { return m_car; }

private:
    Car* m_car;
};

// •Director（指挥者）：构造一个使用 Builder 接口的对象。
class Director {
public:
    const Car* createCar(Builder* builder) {
        builder->buildBrake();
        builder->buildWheel();
        builder->buildEngine();

        return builder->getResult();
    }
};

int main(int argc, const char **argv) {
    Director d;
    Builder* b_baoma = new(std::nothrow) BaomaBuilder();
    const Car* baoma = d.createCar(b_baoma);

    baoma->show();
    return 0;
}
